package edu.faytechcc.csc.messages;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import edu.faytechcc.csc.gui.search.SearchFrame;
import edu.faytechcc.csc.gui.server.AskQuery;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * This class sends and receives messages over a port.
 *
 * @author Stephanie Mckenzie and Jasmin Pastari
 */
public class NetworkConnection
{

    private PrintWriter out;
    private BufferedReader in;
    private ObjectInputStream inObj;
    private ObjectOutputStream outObj;
    private SearchFrame searchFrame;
    private AskQuery askServer;
    private Socket socket;

    /**
     * Constructor that takes a socket
     * 
     * @param socket
     */
    public NetworkConnection(Socket socket)
    {
        this.socket = socket;
    }

    /**
     * Creates an opening for the connection and starts a RecieveObjectsThread.
     *
     * @throws IOException
     */
    public void connectClient() throws IOException
    {
        out = new PrintWriter(socket.getOutputStream(), true);
        inObj = new ObjectInputStream(socket.getInputStream());
        (new RecieveObjectsThread()).start();
    }

    /**
     * Creates an opening for the connection and starts a RecieveMessagesThread.
     *
     * @throws IOException
     */
    public void connectServer() throws IOException
    {
        outObj = new ObjectOutputStream(socket.getOutputStream());
        in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        (new RecieveMessagesThread()).start();
    }

    /**
     * Sets the SearchFrame
     *
     * @param searchFrame
     */
    public void addSearchPanel(SearchFrame searchFrame)
    {
        this.searchFrame = searchFrame;
    }

    /**
     * Sets the AskQuery
     *
     * @param ask
     */
    public void addServer(AskQuery ask)
    {
        this.askServer = ask;
    }

    /**
     * Sends a String.
     *
     * @param message
     */
    public void sendMessages(String message)
    {
        out.println(message);
    }

    /**
     * Sends an Object.
     *
     * @param thing
     */
    public void sendObject(Object thing)
    {
        try
        {
            outObj.writeObject(thing);
        } catch (IOException ex)
        {
        }
    }

    /**
     * Receives Strings and updates the AskQuery set in the addServer method
     * with them.
     */
    private void recieveMessages()
    {
        try
        {
            String inputLine;
            while ((inputLine = in.readLine()) != null)
            {
                askServer.AskGeneralQuery(inputLine);
            }
            out.close();
            in.close();
            if (!socket.isClosed())
            {
                socket.close();
            }
        } catch (IOException e)
        {
            System.out.println("Connection Closed. Messages");
        }
    }

    /**
     * Receives Objects and updates the searchFrame set in the addSearchPanel
     * method with them.
     */
    private void recieveObject()
    {
        try
        {
            Object thing;
            while ((thing = inObj.readObject()) != null)
            {
                searchFrame.updateTable(thing);
            }
            out.close();
            in.close();
            if (!socket.isClosed())
            {
                socket.close();
            }
        } catch (Exception e)
        {
            System.out.println("Connection Closed. Objects");
        }
    }

    /**
     * Thread to receive String messages using the recieveMessages method in
     * this class.
     */
    private class RecieveMessagesThread extends Thread
    {

        @Override
        public void run()
        {
            recieveMessages();
        }
    }

    /**
     * Thread to receive Objects using the recieveObject method in this class.
     */
    private class RecieveObjectsThread extends Thread
    {

        @Override
        public void run()
        {
            recieveObject();
        }
    }
}
